﻿using System;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WMIViewer
{
    public partial class WMIViewer : Form
    {
        private Thread _thread2;

        public WMIViewer()
        {
            InitializeComponent();
        }

        private void WMIViewer_Load(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                var moSearcher = new ManagementObjectSearcher("SELECT * FROM meta_class");
                var moCollection = moSearcher.Get().Cast<ManagementObject>();
                var items = moCollection.OrderBy(m => m.ClassPath.RelativePath).Select(m => new ManagementObjectItem(m)).ToArray();
                fullListBox(listBox1, items);
                changeCountLable(_listBox1CountLable, items.Length);
            });
            
        }

        private void changeCountLable(Label label, int length)
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(()=>changeCountLable(label, length)));
                return;
            }
            label.Text = "Count:" + length;
        }

        private void fullListBox(ListBox listBox, ManagementObjectItem[] objs)
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(()=> fullListBox(listBox, objs)));
                return;
            }

            listBox.Items.AddRange(objs);
        }

        private void fullData(ManagementObject mObj)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var propertyData in mObj.SystemProperties)
            {
                object value = propertyData.Value;
                var array = value as string[];
                if (array != null)
                {
                    sb.Clear();
                    sb.Append("string[" + array.Length + "]:");
                    foreach (var str in array)
                    {
                        sb.Append("["+str+"],");
                    }
                    value = sb.ToString().TrimEnd(',');
                }
                _systemPropertiesData.Rows.Add(propertyData.Name, value, propertyData.Type, propertyData.IsLocal, propertyData.IsArray, propertyData.Origin);
            }
            
            foreach (var propertyData in mObj.Properties)
            {
                object value = propertyData.Value;
                var array = value as string[];
                if (array != null)
                {
                    sb.Clear();
                    sb.Append("string[" + array.Length + "]:");
                    foreach (var str in array)
                    {
                        sb.Append("[" + str + "],");
                    }
                    value = sb.ToString().TrimEnd(',');
                }
                _propertiesData.Rows.Add(propertyData.Name, value, propertyData.Type, propertyData.IsLocal, propertyData.IsArray, propertyData.Origin);
            }
            foreach (var qualifiey in mObj.Qualifiers)
            {
                object value = qualifiey.Value;
                var array = value as string[];
                if (array != null)
                {
                    sb.Clear();
                    sb.Append("string["+array.Length+"]:");
                    foreach (var str in array)
                    {
                        sb.Append("[" + str + "],");
                    }
                    value = sb.ToString().TrimEnd(',');
                }
                _qualifiersData.Rows.Add(qualifiey.Name, value, qualifiey.IsLocal, qualifiey.IsAmended, qualifiey.IsOverridable, qualifiey.PropagatesToInstance, qualifiey.PropagatesToSubclass);
            }
            
        }

        
        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            listBox2.Items.Clear();
            clearData();

            if (_thread2!= null && _thread2.IsAlive)
            {
                _thread2.Abort();
                _thread2 = null;
            }
            
            var selectedItem = listBox1.SelectedItem as ManagementObjectItem;
            if (selectedItem == null)
            {
                return;
            }

            _thread2 = new Thread(() =>
            {
                var managementClass = new ManagementClass(selectedItem.Obj.ClassPath);
                var items = managementClass.GetInstances()
                    .Cast<ManagementObject>()
                    .Select(m => new ManagementObjectItem(m, ManagementObjectItem.ObjStr))
                    .ToArray();
                changeCountLable(_listBox2CountLable, items.Length);
                fullListBox(listBox2, items);
            });
            _thread2.Start();

            fullData(selectedItem.Obj);
        }

        private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            clearData();

            var selectedItem = listBox2.SelectedItem as ManagementObjectItem;
            if (selectedItem == null)
            {
                return;
            }

            fullData(selectedItem.Obj);
        }

        private void clearData()
        {
            _systemPropertiesData.Rows.Clear();
            _propertiesData.Rows.Clear();
            _qualifiersData.Rows.Clear();
        }

        class ManagementObjectItem
        {
            public const int ClassPath = 0;
            public const int RelativePath = 1;
            public const int ObjStr = 2;

            private ManagementObject _obj;
            private int _display = 0;

            public ManagementObjectItem(ManagementObject obj, int display = 1)
            {
                _obj = obj;
                _display = display;
            }

            public ManagementObject Obj
            {
                get { return _obj; }
            }

            public override string ToString()
            {
                switch (_display)
                {
                    case ClassPath:
                        return _obj.ClassPath.ToString();
                    case RelativePath:
                        return _obj.ClassPath.RelativePath;
                    case ObjStr:
                        return _obj.ToString();
                    default:
                        return _obj.ToString();
                }
            }
        }
    }
}
